#!/bin/bash
set -uo pipefail

# Install script dependencies
set -e
cd rspec-tools && pipenv install && cd ..
set +e

# This script runs all tests; it doesn't exit at the first failure.
exit_code=0

readonly ALLOWED_RULE_SUB_FOLDERS=['common'];

# Validate user-visible rule descriptions
# i.e., without rspecator-view.
./ci/generate_html.sh
cd rspec-tools
if pipenv run rspec-tools check-description --d ../out; then
  echo "Rule descriptions are fine"
else
  echo "ERROR: There are invalid rule descriptions"
  exit_code=1
fi
cd ..

# Compute the set of affected rules
git fetch origin "$CIRRUS_DEFAULT_BRANCH"
branch_base_sha=$(git merge-base FETCH_HEAD HEAD)
echo "Comparing against the merge-base: $branch_base_sha"
changeset=$(git diff --name-only "$branch_base_sha"..HEAD)
affected_rules=$(printf '%s\n' "$changeset" | grep '/S[0-9]\+/' | sed 's:\(.*/S[0-9]\+\)/.*:\1:' | sort | uniq)
if printf '%s\n' "$changeset" | grep -qv '/S[0-9]\+/'; then
  echo "Some rpec tools or shared_content changed, validating all rules"
  affected_rules=rules/*
fi

# Validate some properties of the asciidoc:
#
# [properties validated only on affected rules]
#  * Rules should have at least one language specification,
#    unless they are closed or deprecated.
#  * The include:: should have an empty line before and after them.
#  * Only valid languages can be used as subdirectories in rule directories,
#    with the exception of ALLOWED_RULE_SUB_FOLDERS.
#  * Asciidoc files are free or errors and warnings.
#  * ifdef/endif are used appropriatedly.
#
# [properties validated always on all rules]
#  * Rule descriptions can include other asciidoc files from the same rule
#    directory or from shared_content.
#  * All asciidoc files are used/included.

echo "Testing the following rules: ${affected_rules}"
supportedLanguages=$(sed 's/ or//' supported_languages.adoc | tr -d '`,')
for dir in $affected_rules
do
  if [ ! -d "$dir" ]; then
    echo "Apparently $dir is deleted, skipping"
    continue
  fi
  dir=${dir%*/}

  # check if there are language specializations
  subdircount=$(find "$dir" -maxdepth 1 -mindepth 1 -type d | wc -l)
  if [[ "$subdircount" -eq 0 ]]
  then
    # no specializations, that's fine if the rule is deprecated
    if grep -Pq '"status": "(deprecated|closed)"' "$dir/metadata.json"; then
      echo "INFO: deprecated generic rule $dir with no language specializations"
    else
      echo "ERROR: non-deprecated generic rule $dir with no language specializations"
      exit_code=1
    fi
  else
    # Add the full path of all adoc files that were affected for sanitization
    find ~+/"${dir}" -name '*.adoc' >> all_asciidocs

    for language in "${dir}"/*/
    do
      language=${language%*/}
      if [[ ! "${supportedLanguages[*]}" == *"${language##*/}"* ]]; then
        if [[ ! "${ALLOWED_RULE_SUB_FOLDERS[*]}" == *"${language##*/}"* ]]; then
          echo "ERROR: ${language##*/} is not a supported language"
          exit_code=1
        fi
      else
        RULE="$language/rule.adoc"
        if test -f "$RULE"; then
          # Errors emitted by asciidoctor don't include the full path.
          # https://github.com/asciidoctor/asciidoctor/issues/3414
          # To ease debugging, we copy the rule.adoc into tmp_SXYZ_language.adoc
          # and run asciidoctor on them instead.
          # We add the implicit header "Description" to prevent an asciidoctor warning.
          TMP_ADOC="$language/tmp_$(basename "${dir}")_${language##*/}.adoc"
          echo "== Description" > "$TMP_ADOC"
          cat "$RULE" >> "$TMP_ADOC"
        else
          echo "ERROR: no asciidoc file $RULE"
          exit_code=1
        fi
      fi
    done
  fi
done

cd rspec-tools
cat ../all_asciidocs | xargs pipenv run rspec-tools check-asciidoc >validate_asciidoc 2>&1
if [ -s validate_asciidoc ]; then
  echo "ERROR: Invalid asciidoc description:"
  cat validate_asciidoc
  exit_code=1
fi
rm -f validate_asciidoc ../all_asciidocs
cd ..



# Run asciidoctor and fail if a warning is emitted.
# Use the tmp_SXYZ_language.adoc files (see note above).
ADOC_COUNT=$(find rules -name "tmp*.adoc" | wc -l)
if (( ADOC_COUNT > 0 )); then
  if asciidoctor --failure-level=WARNING -o /dev/null rules/*/*/tmp*.adoc; then
    if asciidoctor -a rspecator-view --failure-level=WARNING -o /dev/null rules/*/*/tmp*.adoc; then
      echo "${ADOC_COUNT} documents checked with success"
    else
      echo "ERROR: malformed asciidoc files in rspecator-view"
      exit_code=1
    fi
  else
    echo "ERROR: malformed asciidoc files"
    exit_code=1
  fi
else
  echo "No new asciidoc file changed"
fi
find rules -name "tmp*.adoc" -delete

# Validate file inclusion, cross-references, and other properties.
#
# This part of the validation is extracted in a separate script,
# which is covered by tests unlike what is above this line.
TOPLEVEL=. ./ci/asciidoc_validation/validate.sh || exit_code=1

if (( exit_code == 0 )); then
  echo "Success"
else
  echo "There were errors"
fi
exit $exit_code
